#include "NetworkControl.h"
#include "misc/Debug.h"
#include "misc/Event.h"
#include "server/misc/Config.h"
#include "server/multiProtocol/multiMsg.h"
#include "server/multiProtocol/multiDiscovery.h"
#include "server/multiProtocol/multiJoin.h"
#include "server/multiProtocol/multiRing.h"
#include "server/multiProtocol/multiLeave.h"
#include "server/net/sData.h"
#include "server/net/sKeepAlive.h"
#include "server/net/sDiscovery.h"
#include "server/net/sAnnounce.h"
#include "server/net/sRegister.h"
#include "server/net/sUnRegister.h"
#include "server/file/FileControl.h"
#include "misc/Interface.h"
#include "misc/BigInt/BigIntegerLibrary.hh"
#include <Poco/Thread.h>
#include <Poco/ThreadPool.h>
#include <string.h>
#include <iomanip>
#include <sstream>
#include <iostream>

Poco::Mutex* NetworkControl::mutex = new Poco::Mutex;		// initialize the static mutex pointer
/*********************************************************/
void NetworkControl::run()
{
	Debug& 			DEBUG = Debug::Instance();
	Config&			cfg = Config::Instance();
	Interface& 		iface = Interface::Instance();
	Event*			trafficEvent = Event::Instance(cfg.getUnicastTrafficEvent());
	Event*			jobReadyEvent = Event::Instance(cfg.getActivateProcessingEvent());
	std::string		msg;
	sMsg*			job;

	DEBUG << "NetworkControl :: Thread entering main loop" << std::endl;

	// Main processing loop
	while( true ) {
		// Wait for network traffic
		trafficEvent->wait();
		
		// Check for the halt flag
		mutex->lock();
		if ( halt ) {
			mutex->unlock();
			DEBUG << "NetworkControl :: Thread exiting" << std::endl;
			return;
		}
		mutex->unlock();
	
		// Get the messages from the unicast network & parse them and add valid packets to the job queue
		while( unicast->available() ) {
			Poco::Net::SocketAddress 	sender;
			msg = unicast->pop(sender);
			
			// Attempt to parse it & capture all exceptions 
			try {
				job = sMsg::deserialize(msg);
				if ( job ) {
					mutex->lock();
					job->setSenderAddr(sender);
					jobQueue.push(job);
					mutex->unlock();
					jobReadyEvent->set();
				}

				// Update any keepalive timers if necessary
				if ( getPredecessor().compare(sender.toString()) == 0 ) {
					tPred = Poco::Timestamp();
				}

				if ( getSuccessor().compare(sender.toString()) == 0 ) {
					tSucc = Poco::Timestamp();
				}
			} catch(...) {
				job = 0;
				iface << "Received unicast junk: " << msg << std::endl;
				iface.flush();
			}
		}

		// Get the messages from the multicast network & parse them
		while ( multicast->available() ) {
			msg = multicast->pop();
			MultiMsg* mMsg = 0;

			try {
				mMsg = MultiMsg::deserialize(msg);
				if ( mMsg ) {
					mMsg->execute();
					delete(mMsg);
				}
			} catch (std::exception& e) {
				mMsg = 0;
				iface << "Received multicast junk: " << msg << std::endl;
				iface.flush();
			} catch (...) {
				mMsg = 0;
				iface << "Received multicast junk: " << msg << std::endl;
				iface.flush();
			}
		}

		// Run the multicast protocol code
		runMulticastProtocol();

		// Check if we need to send any keep alive messages ( interval = 1 second )
		if (( !ringInit ) && ( keepalive.elapsed() > 1000000 )) {
			runKeepAlive();
			keepalive = Poco::Timestamp();
		}

	}
	DEBUG << "NetworkControl :: Thread exiting" << std::endl;
}
/*********************************************************/
void NetworkControl::uploadFiles(const std::string& target)
{
	Interface& iface = Interface::Instance();
	FileControl& files = FileControl::Instance();
	Poco::ThreadPool		tPool;

	// Get a file list overview of all files we need to transfer
	std::vector<std::string> list = files.getFiles();
	iface << "Uploading files to: " << target << std::endl;
	iface.flush();

	// Send a put message for every file
	for ( unsigned int i=0; i<list.size(); i++ ) {

		iface << "Uploading file: " << list[i] << std::endl;
		iface.flush();

		// Send all available chunks of the file to the ring
		unsigned long nChunks = (unsigned long)((files.getFileSize(list[i]) / files.getChunkSize())) + 1;
		for ( unsigned long o = 0; o<nChunks; o++ ) {
			if ( files.chunkAvailable(list[i], o) ) {
				std::string data = files.getChunk(list[i], o);

				// Build the data message
				sData 	dat;
				dat.setOrder(i);
				dat.setShell(false);
				dat.setFileName(list[i]);
				dat.setData(data);
				dat.setFileSize(files.getFileSize(list[i]));

				// Transmit the message
				unicast->sendTo(dat.serialize(), target);
				usleep(100);		// Wait a bit, the network is supposed to be slow so we don't want to flood it
			}
		}
	}
}
/*********************************************************/
void NetworkControl::runKeepAlive()
{
	Interface& iface = Interface::Instance();

	// Do we need to send any keepalive messages?
	if ( getLocalAddress().compare(getPredecessor()) != 0 ) {
		if ( tPred.elapsed() > 10000000 ) {
			sKeepAlive ka;
			unicast->sendTo(ka.serialize(), getPredecessor());
			iface << "Predecessor: " << getPredecessor() << " has been inactive for: " << tPred.elapsed() << "µ seconds, sending keepalive packet" << std::endl;
			iface.flush();
		}
	} else {
		tPred = Poco::Timestamp();
	}

	if ( getLocalAddress().compare(getSuccessor()) != 0 ) {
		if ( tSucc.elapsed() > 10000000 ) {
			sKeepAlive ka;
			unicast->sendTo(ka.serialize(), getSuccessor());
			iface << "Successor: " << getSuccessor() << " has been inactive for: " << tSucc.elapsed() << "µ seconds, sending keepalive packet" << std::endl;
			iface.flush();
		}
	} else {
		tSucc = Poco::Timestamp();
	}

	// If nodes haven't responded to a few keep alive messages we remove them from the ring
	if ( tPred.elapsed() > 30000000 ) {
		// Remove the predecessor
		MultiLeave	mLeave;
		mLeave.setAddr(getPredecessor());
		//broadcast(&mLeave);
		mLeave.execute();
		tPred = Poco::Timestamp();
		iface << "Removing node: " << getPredecessor() << std::endl;
		iface.flush();
	}

	if ( tSucc.elapsed() > 30000000 ) {
		// Remove the successor
		MultiLeave	mLeave;
		mLeave.setAddr(getSuccessor());
		mLeave.execute();
		//broadcast(&mLeave);
		tSucc = Poco::Timestamp();
		iface << "Removing node: " << getSuccessor() << std::endl;
		iface.flush();
	}
}
/*********************************************************/
void NetworkControl::runMulticastProtocol()
{
	mutex->lock();

	if ( ringInit ) {
		// Check if enough time has passed to allow the other rings to respond to the discovery message
		if ( startTime.elapsed() < MULTICAST_RING_CREATE_PAUSE) {
		        mutex->unlock();
		        return;
		}

		// Store the local address
		int port;
		std::string host;
		unicast->getLocalAddress(host, port);
		std::ostringstream	ostr;
		ostr << host << ":" << port;
		node.addr = ostr.str();

		// Enough time has passed, check if we can join an existing ring
		if ( nodes.empty() ) {
			// Calculate our hash value
			BigUnsigned	maxHash = BigUnsignedInABase(MAX_HASH_VALUE, 16);
			BigUnsigned	localHash = maxHash / 2;

			// Convert our hash from a number to a string
			std::ostringstream      oss;
			oss.flags(std::ios::hex);
			oss << localHash;
			node.hash = oss.str();

			// Since we are alone in the ring we add ourself as predecessor and successor
			node.predecessor = node.addr;
			node.successor = node.addr;

			// Now we broadcast this new ring using a multiring message
			MultiRing	mRing;
			mRing.setPredecessorAddr(node.predecessor);
			mRing.setSuccessorAddr(node.successor);
			mRing.setAddr(node.addr);
			mRing.setHash(node.hash);
			multicast->send(mRing.serialize());

			// Set the initialization flag to false & return
			ringInit = false;
			mutex->unlock();
			return;

		} else {
			// Calculate the difference between the last and first node in the ring
			BigUnsigned 	diff(0);
			BigUnsigned 	temp(0);
			BigUnsigned	final(0);
			BigUnsigned 	first = BigUnsignedInABase(nodes[0].hash, 16);
			BigUnsigned	last = BigUnsignedInABase(nodes[nodes.size()-1].hash, 16);
			BigUnsigned	max = BigUnsignedInABase(MAX_HASH_VALUE, 16);
			diff = (max - last) + first;
			unsigned int pre = nodes.size()-1;
			unsigned int post = 0;

			// Find the spot with the largest gap in hash value
			for ( unsigned int i = 0; i<(nodes.size()-1); i++ ) {
				first = BigUnsignedInABase(nodes[i].hash, 16);
				last = BigUnsignedInABase(nodes[i+1].hash, 16);
				temp = last - first;

				if ( temp > diff ) {
					diff = temp;
					pre = i;
					post = i+1;
				}
			}

			// Calculate our final hash value
			first = BigUnsignedInABase(nodes[pre].hash, 16);
			final = first + (diff / 2);
			if (( pre == nodes.size()-1 ) && ( post == 0 )) {
				if ( final > max ) final = final - max;
			}

			// Convert our hash from a number to a string
			std::ostringstream      oss;
			oss.flags(std::ios::hex);
			oss << final;
			node.hash = oss.str();

			node.predecessor = nodes[pre].addr;
			node.successor = nodes[post].addr;

			// Build a ringJoin message and broadcast it
			MultiJoin	mJoin;
			mJoin.setPred(node.predecessor);
			mJoin.setSucc(node.successor);
			mJoin.setAddr(node.addr);
			mJoin.setHash(node.hash);
			multicast->send(mJoin.serialize());

			// Set the init flag to false and return
			ringInit = false;
			mutex->unlock();
			return;
		}
	}

	// Keep track of the keep alive timers
	if ( startTime.elapsed() > MULTICAST_RING_KEEPALIVE ) {
		startTime = Poco::Timestamp();
		MultiRing	mRing;
		mRing.setPredecessorAddr(node.predecessor);
		mRing.setSuccessorAddr(node.successor);
		mRing.setAddr(node.addr);
		mRing.setHash(node.hash);
		broadcast(&mRing);
	}

	mutex->unlock();
}
/*********************************************************/
void NetworkControl::send(const sMsg* msg)
{
	Interface& 		iface = Interface::Instance();

	mutex->lock();
	int port;
	std::string host;
	unicast->getResponseAddress(host, port);
	std::ostringstream ostr;
	ostr << host << ":" << port;
	std::string m = msg->serialize();
	unsigned long id = msg->getID();

	// Add the message to the waiting for Ack queue & send it
	ackmap[ostr.str()][id] = m;	
	unicast->send(m);
	mutex->unlock();

	// Wait for the ack
	int attempts = 0;
	while (!waitForAck(ostr.str(), id) && (attempts < 5)) {
		attempts++;
		mutex->lock();
		unicast->send(m);
		mutex->unlock();
		iface << "Failed to send message, no ack returned... retrying" << std::endl;
		iface.flush();
	}
}
/*********************************************************/
void NetworkControl::sendTo(const sMsg* msg, const std::string& target)
{
	Interface& iface = Interface::Instance();

	mutex->lock();
	std::string m = msg->serialize();
	ackmap[target][msg->getID()] = m;
	unicast->sendTo(m, target);
	mutex->unlock();

	// Wait for the ack
	int attempts = 0;
	while (!waitForAck(target, msg->getID()) && (attempts < 5)) {
		attempts++;
		mutex->lock();
		unicast->sendTo(m, target);
		mutex->unlock();
		iface << "Failed to send message, no ack returned... retrying" << std::endl;
		iface.flush();
	}
}
/*********************************************************/
void NetworkControl::broadcast(const MultiMsg* msg)
{
	mutex->lock();
	multicast->send(msg->serialize());
	mutex->unlock();
}
/*********************************************************/
bool NetworkControl::waitForAck(const std::string& addr, const unsigned long& id)
{
	mutex->lock();
	bool acked = false;
	int time = 0;
	while ( !acked && (time < 5000)) {
		ACKMAP_::iterator it = ackmap.find(addr);
		if ( it != ackmap.end() ) {
			std::map<unsigned long, std::string>::iterator it2 = it->second.find(id);
			if ( it2 == it->second.end() ) {
				acked = true;
			}
		} else {
			acked = true;
		}
		mutex->unlock();
		usleep(100000);
		time += 100;
		mutex->lock();
	}
	mutex->unlock();	
	return acked;
}
/*********************************************************/
bool NetworkControl::getRingActive() const
{
	mutex->lock();
	bool result;
	if ( ringInit ) result = false;
	else result = true;
	mutex->unlock();
	return result;
}
/*********************************************************/
std::string NetworkControl::getSuccessorHash() const
{
	mutex->lock();
	std::string hash;

	// First we search the index of our own node in the ring
	unsigned int index;
	for ( index = 0; index<nodes.size(); index++ ) {
		if ( nodes[index].addr == node.addr ) {
			break;
		}
	}

	// Extract the successor hash
	if ( (index+1) >= nodes.size() ) {
		hash = nodes[0].hash;
	} else {
		hash = nodes[index+1].hash;
	}

	mutex->unlock();
	return hash;
}
/*********************************************************/
std::string NetworkControl::getPredecessorHash() const
{
	mutex->lock();
	std::string hash;

	// First we search the index of our own node in the ring
	unsigned int index;
	for ( index = 0; index<nodes.size(); index++ ) {
		if ( nodes[index].addr == node.addr ) {
			break;
		}
	}

	// Extract the predecessor hash
	if ( index == 0 ) {
		hash = nodes[nodes.size()-1].hash;
	} else {
		hash = nodes[index-1].hash;
	}
	mutex->unlock();

	return hash;
}
/*********************************************************/
std::string NetworkControl::getRingInformation() const
{
	std::ostringstream	 ostr;

	mutex->lock();
	ostr << "Ring in multicastgroup: " << multicast->getGroupIP() << ":" << multicast->getGroupPort() << std::endl;
	ostr << "--------------------------------------" << std::endl;
	ostr << std::setw(25) << std::left  << "Addr" << std::setw(25) << "Pred" << std::setw(25) << "Succ" << std::setw(40) << "Hash" << std::endl;
	for ( unsigned int a = 0; a<nodes.size(); a++ ) {
		ostr << std::setw(25) << nodes[a].addr << std::setw(25) << nodes[a].predecessor << std::setw(25) << nodes[a].successor << std::setw(40) << nodes[a].hash << std::endl; 
	}
	mutex->unlock();

	return ostr.str();
}
/*********************************************************/
void NetworkControl::setRingUpdate(bool b)
{
	mutex->lock();
	ringChange = b;
	mutex->unlock();
}
/*********************************************************/
std::string NetworkControl::getLocalAddress() const
{
	int port;
	std::string host;
	std::ostringstream	ostr;

	mutex->lock();
	unicast->getLocalAddress(host, port);
	mutex->unlock();

	ostr << host << ":" << port;
	return ostr.str();
}
/*********************************************************/
std::string NetworkControl::getLocalHash() const
{
	mutex->lock();
	std::string h = node.hash;
	mutex->unlock();
	return h;
}
/*********************************************************/
std::string NetworkControl::getPredecessor() const
{
	mutex->lock();
	std::string p = node.predecessor;
	mutex->unlock();
	return p;
}
/*********************************************************/
std::string NetworkControl::getSuccessor() const
{
	mutex->lock();
	std::string s = node.successor;
	mutex->unlock();
	return s;
}
/*********************************************************/
bool NetworkControl::getRingUpdate() const
{
	mutex->lock();
	bool change = ringChange;
	mutex->unlock();
	return change;
}
/*********************************************************/
sMsg* NetworkControl::pop()
{
	mutex->lock();
	sMsg* job = jobQueue.front();
	jobQueue.pop();
	mutex->unlock();
	return( job );
}
/*********************************************************/
bool NetworkControl::available() const
{
	mutex->lock();
	if ( jobQueue.empty() ) {
		mutex->unlock();
		return( false );
	} else {
		mutex->unlock();
		return( true );
	}
}
/*********************************************************/
NetworkControl& NetworkControl::Instance()
{
	mutex->lock();
	static NetworkControl pInstance;	
	mutex->unlock();
	return pInstance; 			// return the address of the sole instance
}
/*********************************************************/
void NetworkControl::detectNameServer()
{
	// Fetch the configuration instance
	Config& cfg = Config::Instance();

	// Create a temporary multicast class for communication with the nameserver
	MultiNet* multi = new( MultiNet )(cfg.getNetworkInterface());
	multi->start(cfg.getMulticastTrafficEvent());
	multi->joinGroup(Poco::Net::SocketAddress(cfg.getNameServerGroup()).host().toString(), Poco::Net::SocketAddress(cfg.getNameServerGroup()).port());
	multi->setLoopback(true);

	// Send a discovery, so the nameserver replies with an announce
	sDiscovery	disc;
	multi->send(disc.serialize());

	// Wait for the reply from the nameserver
	Event* 			check = Event::Instance("CHECK_EVENT");
	Timer  			clock("CHECK_EVENT", 5000, true);
	Poco::Timestamp		time;
	bool 			found = false;

	while ( !found ) {
		check->wait();

		if ( time.elapsed() > (cfg.getNameServerDelay()*1000) ) {
			sleep(5);
			multi->stop();
			delete( multi );
			multi = 0;
			clock.stop();
			throw(std::logic_error("NameServer timeout error"));
		}

		while ( multi->available() ) {
			std::string msg = multi->peek();
			multi->pop();

			sMsg* packet = sMsg::deserialize(msg);
			if ( packet ) {
				sAnnounce* ann = dynamic_cast<sAnnounce*>(packet);
				if ( ann ) {
					ann->execute();
					found = true;
					clock.stop();
					delete( ann );
					break;
				} else {
					delete( packet );
				}
			}
		}
	}

	// Clean up the temporary multicasting class
	multi->stop();
	delete(multi);

	// Fetch our host address from the UDPNet class
	int port;
	std::string addr;
	unicast->getLocalAddress(addr, port);
	std::ostringstream ostr;
	ostr << addr << ":" << port;

	// Extract the port from the ringname
	std::ostringstream oss;
	std::string ringport = cfg.getRingName().substr(4,1000);
	oss << cfg.getNetworkMulticastGroup() << ":" << ringport;

	sRegister	reg;
	reg.setHostAddr(ostr.str());
	reg.setRingName(cfg.getRingName());
	reg.setRingAddr(oss.str());

	// Set the ring port in the configuration class
	unsigned int ringP;
	if ( sscanf(ringport.c_str(), "%u", &ringP ) != 1 ) {
		throw(std::logic_error("Invalid ring port detected in ringname!"));
	}
	cfg.setRingPort(ringP);

	// Send the register message to the nameserver
	unicast->sendTo(reg.serialize(), nsAddr.toString());
}
/*********************************************************/
void NetworkControl::start() 
{
	// Fetch the configuration instance
	Config& cfg = Config::Instance();

	// Get the events, we reset these in case the class is started & then stopped again
	Event*			trafficEvent = Event::Instance(cfg.getUnicastTrafficEvent());
	Event*			jobReadyEvent = Event::Instance(cfg.getActivateProcessingEvent());

	// Run the start code only when the thread isn't running!
	mutex->lock();
	if ( lThread.isRunning() ) {
		mutex->unlock();
		return;
	} else {
		// Create the network unicast class
		Poco::Net::NetworkInterface iface = Poco::Net::NetworkInterface::forName(cfg.getNetworkInterface());
		unsigned int av_port = UDPNet::getAvailablePort(iface.address().toString(), cfg.getNetworkUnicastPortRangeMin(), cfg.getNetworkUnicastPortRangeMax());
		unicast = new( UDPNet )(iface.address().toString(), av_port);
		unicast->start(cfg.getUnicastTrafficEvent());

		// store the local information
		int port;
		std::string host;
		unicast->getLocalAddress(host, port);
		std::ostringstream	ostr;
		ostr << host << ":" << port;
		node.addr = ostr.str();

		// Detect the nameserver in order to obtain the necessary parameters to join/create a ring
		try {
			detectNameServer();
		} catch(...) {
			unicast->stop();
			delete( unicast );
			return;
		}
	
		// Start the multicast class
		multicast = new( MultiNet )(cfg.getNetworkInterface());
		multicast->start(cfg.getMulticastTrafficEvent());
		multicast->joinGroup(cfg.getNetworkMulticastGroup(), cfg.getRingPort());	// Join a multicasting group
		multicast->setLoopback(true);

		// We want the multicast code to run frequently at specified time intervals so we set a timer for that
		mTimer = new( Timer )(cfg.getUnicastTrafficEvent(),MULTICAST_PROTOCOL_TIMER,true);
	
		// Set the halt & ring flags
		halt = false;
		ringChange = false;
		ringInit = true;
		node.hash = "";
		node.predecessor = "";
		node.successor = "";

		// Clear the ring vector from all data
		nodes.clear();

		// Clear the job queue
		while ( !jobQueue.empty() ) {
			sMsg*	temp = jobQueue.front();
			jobQueue.pop();
			delete( temp );
		}

		// Reset the events
		trafficEvent->reset();
		jobReadyEvent->reset();

		// Start the local thread
		lThread.start((*this));
		mutex->unlock();
		usleep(100);		// Wait a bit for the thread to succesfully boot

		// Send a discovery message to discover any existing rings
		MultiDiscovery mDisc;
		multicast->send(mDisc.serialize());

		// Create the delay timer for the ring configuration
		startTime = Poco::Timestamp();
		keepalive = Poco::Timestamp();
	}
}
/*********************************************************/
void NetworkControl::stop()
{
	// Fetch the configuration instance
	Config& cfg = Config::Instance();

	// Are we part of a ring? if so ... send a leave message
	if (( !ringInit ) && ( multicast )) {
		// Store the predecessor address for later use ( it will be deleted when we send the multiLeave message! )
		std::string target = getPredecessor();

		// Send the multileave message
		MultiLeave	mLeave;
		mLeave.setAddr(getLocalAddress());
		multicast->send(mLeave.serialize());

		// Unregister ourselves at the nameserver
		sUnRegister	unReg;
		unReg.setHostAddr(getLocalAddress());
		unReg.setRingName(cfg.getRingName());
		unicast->sendTo(unReg.serialize(), nsAddr.toString());

		// We need to upload all files to the still existing ring
		if (( getPredecessor().compare(getLocalAddress()) == 0 ) && ( getSuccessor().compare(getLocalAddress()) == 0 )) {
			// No ring exists so we do nothing
		} else {
			uploadFiles(target);
		}
	}

	// Get the events, we reset these in case the class is started & then stopped again
	Event*			trafficEvent = Event::Instance(cfg.getUnicastTrafficEvent());
	Event*			jobReadyEvent = Event::Instance(cfg.getActivateProcessingEvent());

	// If the thread is not running... do nothing
	if ( !lThread.isRunning() ) return;

	// Stop the thread
	mutex->lock();
	halt = true;
	trafficEvent->set();
	mutex->unlock();
	while ( lThread.isRunning() ) {
		trafficEvent->set();
		lThread.tryJoin(25);
	}

	// Stop the unicast class
	mutex->lock();
	if ( unicast ) {
		unicast->stop();
		delete(unicast);
		unicast = 0;
	}

	// Stop the multicast class
	if ( multicast) {
		multicast->stop();
		multicast->leaveGroup();
		delete( multicast );
		multicast = 0;
	}	

	// Delete the multicasting protocol timer
	if ( mTimer ) delete( mTimer );

	// Reset the flags to false
	ringChange = false;
	ringInit = false;
	node.hash = "";
	node.predecessor = "";
	node.successor = "";
	node.addr = "";

	// Reset the events
	trafficEvent->reset();
	jobReadyEvent->reset();
	mutex->unlock();
}
/*********************************************************/
unsigned long NetworkControl::getID() 
{
	mutex->lock();
	unsigned long a = counter;
	counter++;
	mutex->unlock();
	return a;
}
/*********************************************************/
std::string NetworkControl::getNetworkInterface()
{
	Poco::Net::NetworkInterface::NetworkInterfaceList ifs = Poco::Net::NetworkInterface::list();
	for (Poco::Net::NetworkInterface::NetworkInterfaceList::const_iterator it = ifs.begin(); it != ifs.end(); ++it)
	{
		if (it->supportsIPv4() && it->address().isUnicast() && !it->address().isLoopback())
			return( it->name() );
	}
	return( "" );
}
/*********************************************************/
NetworkControl::NetworkControl()
{
	// Initial values for the network classes
	unicast = 0;
	multicast = 0;
	counter = 0;

	// Initial flags
	halt = false;
}
/*********************************************************/
NetworkControl::~NetworkControl()
{
	mutex->lock();
	if ( unicast ) delete( unicast );
	if ( multicast ) delete( multicast );
	mutex->unlock();
	delete(mutex);
	mutex = 0;
}
